#ifndef GLOBJECT_H
#define GLOBJECT_H

#include "GLModel.h"
#include "GLTexture.h"
#include "../core/vector3.h"
#include "../core/String.h"
#include "../core/Color.h"
#include "../core/foreach.h"
#include "../tinyxml/tinyxml.h"

#define GLRENDER_NORMAL     0
#define GLRENDER_SELECT     1


class GLObject;

class GLBehavior
{
public:
    GLBehavior(GLObject* obj) : object(obj) { }
    virtual ~GLBehavior() { }

    virtual void onRender() { }
    virtual void onUpdate(float dt) { }

    GLObject *object;
};


typedef std::list<GLObject*> GLObjectList;
typedef std::list<GLBehavior*> GLBehaviorList;


class GLObject
{
public:
    GLObject(GLObject* obj);
    virtual ~GLObject();

    //callbacks
    virtual void onRender();
    virtual void onPreRender()      { }
    virtual void onPostRender()     { }
    virtual void onUpdate(float dt) { }
    virtual void onNewPart(GLObject* obj) { }
    virtual void onNewBehavior(GLBehavior* bhv) { }

    //control
    void reset();
    void render(int flags = 0);
    void update(float dt);
    int pickObjectId(int x, int y, float sense);

    GLObject* importXml(const char* filename);

    //construct
    inline GLObject* setModel(GLModel* m)       { model = m; return this; }
    inline GLObject* setTexture(GLTexture* t)   { texture = t; return this; }
    inline GLObject* setColor(Color c)          { color = c; return this; }
    inline GLObject* setScale(float s)          { scale = s; return this; }
    inline GLObject* setBoxCenter(vector3f v)   { box_center = v; return this; }
    inline GLObject* setBoxSize(vector3f v)     { box_size = v; render_box = true; return this; }
    inline GLObject* setPosition(float x, float y, float z) { position.set(x, y, z); return this; }
    inline GLObject* setRotation(float x, float y, float z) { rotation.set(x, y, z); return this; }
    inline GLObject* setName(const char* s)     { name = s; return this; }
    inline GLObject* setSelectId(int id)        { selectId = id; return this; }
    inline GLObject* setRootObject(GLObject* obj)           { rootObject = obj; return this; }
    inline GLObject* getObject()                { return children.front(); }

    template <class T> T* createObject()
    {
        T* obj = new T(this);
        children.push_back(obj);
        return obj;
    }
    GLObject* createObject();
    void destroyObjects();

    template <class T> T* createBehavior()
    {
        T* bhv = new T(this);
        behaviors.push_back(bhv);
        onNewBehavior(bhv);
        return bhv;
    }
    void destroyBehaviors();

    GLModel*    model;
    GLTexture*  texture;
    Color       color;
    vector3f    position;
    vector3f    rotation;
    float       scale;
    vector3f    box_center;
    vector3f    box_size;
    bool        render_box; /* REMOVE ME !!! */
    String      name;
    int         selectId;

private:
    void parseXmlNode(TiXmlElement* elem, GLObject* root);

    GLObject*       parent;
    GLObject*       rootObject;
    GLObjectList    children;
    GLBehaviorList  behaviors;
};

#endif // GLOBJECT_H
